
//--------------------------------------------------------------------//
//     此代码由T4模板自动生成										  //
//	   生成时间 2020-08-22 14:35:14 	                              //
//	   描述：定时任务
//--------------------------------------------------------------------//

using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using Dapper;
using Newtonsoft.Json.Linq;
using RayD.Core;
using RayD.Repository;
using RayD.Repository.Entites.SystemModule;
using Quartz;
using System;
using System.ComponentModel;
using System.Reflection;
using Castle.Core.Internal;

namespace RayD.App.SystemModule
{
    public class JobApp
    {
        #region 构造函数注入
        private IRepository BaseRepository;
        private LogApp _logService;
        private IScheduler _scheduler;
        public JobApp(IRepository repository, LogApp logService, IScheduler scheduler)
        {
            this.BaseRepository = repository;
            this._logService = logService;
            this._scheduler = scheduler;
        }
        #endregion

        #region 获取数据
        /// <summary>
        /// 获取列表数据
        /// <summary>
        /// <param name=\"queryJson\">查询参数</param>
        /// <returns></returns>
        public IEnumerable<JobEntity> GetList(string queryJson)
        {
            var expression = LinqExtensions.True<JobEntity>();
            var queryParam = queryJson.ToJObject();
            return this.BaseRepository.IQueryable(expression);
        }
        #endregion

        #region 提交数据

        /// <summary>
        /// 保存实体数据（新增、修改）
        /// <summary>
        /// <param name="formEntity">数据实体</param>
        /// <returns></returns>
        [RemoveCache]
        public virtual (bool, string) SaveForm(JobEntity formEntity)
        {
            //字段验重
            if (ValidateExist(formEntity.B_Id, "B_JobName", formEntity.B_JobName)) return (false, "任务名称已存在！");
            if (!formEntity.B_Id.IsEmpty())
            {
                if (formEntity.B_EnabledMark == EnabledMark.Enabled) //运行中
                {
                    return (false, "请先停止该任务！");
                }
                //编辑(Null、主键不会更改)
                formEntity.Modify();
                this.BaseRepository.Update(formEntity);
            }
            else
            {
                //新增
                formEntity.Create();
                this.BaseRepository.Insert(formEntity);
            }
            return (true, "保存成功！");
        }
        /// <summary>
        /// 删除实体数据
        /// <summary>
        /// <param name="formEntity">数据实体</param>
        /// <returns></returns>
        [RemoveCache]
        public virtual (bool, string) DeleteForm(JobEntity formEntity)
        {
            if (formEntity.B_EnabledMark == EnabledMark.Enabled) //运行中
            {
                return (false, "请先停止该任务！");
            }
            this.BaseRepository.Delete(formEntity);
            return (true, "删除成功！");
        }

        #endregion   

        #region 数据验证
        /// <summary>
        /// 验证字段值是否存在
        /// </summary>
        /// <param name="id">实体主键</param>
        /// <param name="field">字段名</param>
        /// <param name="value">字段值</param>
        /// <returns></returns>
        public bool ValidateExist(string id, string field, string value)
        {
            var expression = LinqExtensions.True<JobEntity>();
            if (!string.IsNullOrEmpty(id))
            {
                expression = expression.And(t => t.B_Id != id);
            }
            return this.BaseRepository.IQueryable(expression).Exist(field, value);
        }
        #endregion

        #region 定时任务相关操作
        /// <summary>
        /// 返回系统的job接口
        /// </summary>
        /// <returns></returns>
        public List<JobCallModel> QueryLocalJobCalls()
        {
            List<JobCallModel> res = new List<JobCallModel>();
            //反射获取所有Job,返回其 完全限定名 及 描述
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces()
                    .Contains(typeof(IJob))))
                .ToList();
            foreach (var type in types)
            {
                JobCallModel jobCallModel = new JobCallModel();
                jobCallModel.value = type.FullName;
                if (type.IsDefined(typeof(DescriptionAttribute), true))
                {
                    var des = type.GetCustomAttribute(typeof(DescriptionAttribute), true) as DescriptionAttribute;
                    jobCallModel.des = des.Description;
                }
                res.Add(jobCallModel);
            }
            return res;
        }
        /// <summary>
        /// 停止/运行 任务
        /// </summary>
        /// <param name="formEntity"></param>
        /// <returns></returns>
        [RemoveCache]
        public virtual (bool, string) ChangeState(JobEntity formEntity)
        {
            //终端验证
            if (!AppSettings.JobOption.Enabled)
            {
                return (false, "操作失败，当前服务终端定时功能未开启！");
            }
            if (AppSettings.JobOption.SubjectTerminal != formEntity.B_JobTerminal)
            {
                return (false, "操作失败，当前服务终端与任务执行终端不同，请在相应的终端进行操作！");
            }

            if (formEntity.B_EnabledMark == EnabledMark.Disabled) //停止
            {
                TriggerKey triggerKey = new TriggerKey(formEntity.B_Id);
                // 停止触发器
                _scheduler.PauseTrigger(triggerKey);
                // 移除触发器
                _scheduler.UnscheduleJob(triggerKey);
                // 删除任务
                _scheduler.DeleteJob(new JobKey(formEntity.B_Id));

                #region 记录日志(txt)
                Logger.Log(LogCategory.Quartz, new string[] { $"停止了定时任务：{ formEntity.B_JobName }" });
                #endregion

                #region 记录日志(数据库)
                var userinfo = AuthenticationHelper.LoginUserInfo;
                _logService.WriteLog(LogCategory.Quartz
                    , LogExecuteResult.Success
                    , $"停止了定时任务：{formEntity.B_JobName}"
                    , ""
                    , formEntity.B_JobCall
                    , formEntity.B_JobCallParams
                    , ""
                    , ""
                    , $"{userinfo.account}({userinfo.realName})"
                    , userinfo.userId
                    , formEntity.B_JobName);
                #endregion
            }
            else  //启动
            {
                //获取Job类型
                var jobType = AppDomain.CurrentDomain.GetAssemblies()
                    .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces()
                        .Contains(typeof(IJob)) && t.FullName.Equals(formEntity.B_JobCall)))?.FirstOrDefault();

                var jobBuilderType = typeof(JobBuilder);
                var method = jobBuilderType.GetMethods().FirstOrDefault(
                        x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) &&
                             x.IsGenericMethod && x.GetParameters().Length == 0)
                    ?.MakeGenericMethod(jobType);

                var jobBuilder = (JobBuilder)method.Invoke(null, null);

                IJobDetail jobDetail = jobBuilder.WithIdentity(formEntity.B_Id).Build();
                jobDetail.JobDataMap[Define.JOBMAPKEY] = formEntity.B_Id;  //传递job信息
                ITrigger trigger = TriggerBuilder.Create()
                    .WithCronSchedule(formEntity.B_Cron)
                    .WithIdentity(formEntity.B_Id)
                    .StartNow()
                    .Build();
                _scheduler.ScheduleJob(jobDetail, trigger);

                #region 记录日志(txt)
                Logger.Log(LogCategory.Quartz, new string[] { $"启动了定时任务：{ formEntity.B_JobName }" });
                #endregion

                #region 记录日志(数据库)
                var userinfo = AuthenticationHelper.LoginUserInfo;
                _logService.WriteLog(LogCategory.Quartz
                    , LogExecuteResult.Success
                    , $"启动了定时任务：{formEntity.B_JobName}"
                    , ""
                    , formEntity.B_JobCall
                    , formEntity.B_JobCallParams
                    , ""
                    , ""
                    , $"{userinfo.account}({userinfo.realName})"
                    , userinfo.userId
                    , formEntity.B_JobName);
                #endregion
            }
            //更新实体
            formEntity.Modify();
            this.BaseRepository.Update(new JobEntity() { B_Id = formEntity.B_Id, B_EnabledMark = formEntity.B_EnabledMark });
            return (true, "操作成功！");
        }

        /// <summary>
        /// 记录任务运行结果
        /// </summary>
        /// <param name="jobId">任务Id</param>
        [RemoveCache]
        public virtual void Record(string jobId)
        {
            var job = BaseRepository.FindEntity<JobEntity>(jobId);
            if (job == null)
            {
                //记录定时日志
                _logService.WriteLog(LogCategory.Quartz
                    , LogExecuteResult.Fail
                    , $"未能找到定时任务：{jobId}"
                    , ""
                    , ""
                    , ""
                    , ""
                    , ""
                    , "Quartz"
                    , jobId
                    , "");
                return;
            }
            //更新实体
            job.B_RunCount++;
            job.B_LastRunTime = DateTime.Now.ToCstTime();
            BaseRepository.Update(job);

            #region 记录日志(txt)
            Logger.Log(LogCategory.Quartz, new string[] { $"运行了定时任务：{job.B_JobName}" });
            #endregion

            #region 记录日志(数据库)
            _logService.WriteLog(LogCategory.Quartz
                , LogExecuteResult.Success
                , $"运行了定时任务：{job.B_JobName}"
                , ""
                , job.B_JobCall
                , job.B_JobCallParams
                , ""
                , ""
                , "Quartz"
                , jobId
                , job.B_JobName);
            #endregion
        }

        #endregion
    }
}

